/**
 * @file i2c_master.c
 * @date 2017-12-20
 *
 * NOTE:
 * This file is generated by DAVE. Any manual modification done to this file will be lost when the code is regenerated.
 */
/**
 * @cond
 ***********************************************************************************************************************
 * I2C_MASTER v4.1.24 Configures USIC channel to transmit & receive data using I2C protocol.
 *
 * Copyright (c) 2015-2017, Infineon Technologies AG
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification,are permitted provided that the
 * following conditions are met:
 *
 *   Redistributions of source code must retain the above copyright notice, this list of conditions and the  following
 *   disclaimer.
 *
 *   Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
 *   following disclaimer in the documentation and/or other materials provided with the distribution.
 *
 *   Neither the name of the copyright holders nor the names of its contributors may be used to endorse or promote
 *   products derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE  FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY,OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT  OF THE
 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * To improve the quality of the software, users are encouraged to share modifications, enhancements or bug fixes
 * with Infineon Technologies AG (dave@infineon.com).
 ***********************************************************************************************************************
 *
 * Change History
 * --------------
 *
 * 2015-02-16:
 *     - Initial version<br>
 *
 * 2015-06-10:
 *     - AbortTransmit and AbortReceive API return type modified. <br>
 *
 * 2015-07-31:
 *     - DMA support APIs added
 *
 * 2017-01-19:
 *     - Avoid unintended interrupts when filling FIFO
 *
 * 2017-11-17:
 *     - Use tx_irqn of channel config structure in the call of NVIC_ClearPendingIRQ()
 *
 * 2017-12-20:
 *     - Fix TX DMA issues
 *
 * @endcond
 *
 */
/***********************************************************************************************************************
 * HEADER FILES
 **********************************************************************************************************************/
#include "i2c_master.h"

/***********************************************************************************************************************
 * MACROS
 **********************************************************************************************************************/
#define I2C_MASTER_TDF_RECEIVE_ACK             (0x0200U)
#define I2C_MASTER_TDF_RECEIVE_NACK       (3U << 8U)
#define I2C_MASTER_DMA_SRC_DST_TR_WIDTH_MASK   (0x7EU)
#define I2C_MASTER_DMA_SRC_ADDR_INC_MASK       (0x600U)
#define I2C_MASTER_DMA_SRC_ADDR_INC_POS        (9U)
#define I2C_MASTER_DMA_SRC_TRANSFER_WIDTH_POS  (4U)
#define I2C_MASTER_DMA_DST_TRANSFER_WIDTH_POS  (1U)

#define I2C_DMA_MAX_BLOCK_SIZE (4095U)

/***********************************************************************************************************************
 * LOCAL DATA
 **********************************************************************************************************************/

/***********************************************************************************************************************
 * LOCAL ROUTINES
 **********************************************************************************************************************/
 /*
 * Function monitors the configured protocol interrupt flags. It is called from the protocol interrupt
 * service handler.
 * Function reads the status of the USIC channel and checks for configured flags in the app UI.
 * If any callback function is provided in the app UI, it will be called when the selected flag is set.
 *
 * I2C_MASTER_t * pointer to the I2C_MASTER APP instance handle
 *
 */
void I2C_MASTER_ProtocolHandler(I2C_MASTER_t * const handle);

#if ((I2C_MASTER_INTERRUPT_TX_ENABLED == 1) || (I2C_MASTER_INTERRUPT_RX_ENABLED == 1))
static uint32_t calculate_minfifosize(uint32_t a, uint32_t b)
{
  uint32_t result;

  if (a < b)
  {
    result = a;
  }
  else
  {
    result = b;
  }
  return (result);
}
#endif

#if ((I2C_MASTER_INTERRUPT_TX_ENABLED == 1) || (I2C_MASTER_INTERRUPT_RX_ENABLED == 1) || \
    (I2C_MASTER_DIRECT_TX_ENABLED == 1) || (I2C_MASTER_DIRECT_RX_ENABLED == 1))
static void I2C_MASTER_lSendStart_Or_RepeatedStart(I2C_MASTER_t * handle, const uint32_t address,
                                               const XMC_I2C_CH_CMD_t cmd);
#endif

#if ((I2C_MASTER_INTERRUPT_TX_ENABLED == 1) || (I2C_MASTER_INTERRUPT_RX_ENABLED == 1))
static void I2C_MASTER_lSendStop_JumpTo_TxCallback(I2C_MASTER_t *const handle);
#endif

#if(I2C_MASTER_INTERRUPT_TX_ENABLED == 1)
static void I2C_MASTER_AbortTransmitIRQ(const I2C_MASTER_t *const handle);
#endif

#if (I2C_MASTER_INTERRUPT_RX_ENABLED == 1)
static void I2C_MASTER_lSendStop_JumpTo_RxCallback(I2C_MASTER_t *const handle);
static void I2C_MASTER_lReconfigureRxFIFO(const I2C_MASTER_t * const handle, uint32_t data_size);

static void I2C_MASTER_lReceive_FIFOData(I2C_MASTER_t * const handle, bool send_start, const uint32_t address,
                                         const uint32_t count);

static void I2C_MASTER_lReceive_StdData(I2C_MASTER_t * const handle, bool send_start, const uint32_t address);
static void I2C_MASTER_lAbortReceiveIRQ(const I2C_MASTER_t *const handle);
#endif


#if (I2C_MASTER_DIRECT_TX_ENABLED == 1)
static I2C_MASTER_STATUS_t I2C_MASTER_lStartTransmitPolling(I2C_MASTER_t *const handle, bool send_start,
                                                        const uint32_t slave_address, uint8_t *data,uint32_t size,
                              bool send_stop);
#endif
#if I2C_MASTER_DIRECT_RX_ENABLED
static I2C_MASTER_STATUS_t I2C_MASTER_lStartReceivePolling(I2C_MASTER_t *const handle, bool send_start,uint32_t address,
                                                       uint8_t *data, uint32_t count, bool send_stop,
                               bool send_nack);
#endif
#if (I2C_MASTER_DMA_TX_ENABLED == 1)
static void I2C_MASTER_lAbortTransmitDMA(const I2C_MASTER_t *const handle);
#endif
#if (I2C_MASTER_DMA_RX_ENABLED == 1)
static void I2C_MASTER_lAbortReceiveDMA(const I2C_MASTER_t *const handle);
#endif

#if (I2C_MASTER_DMA_TX_ENABLED == 1) && (I2C_MASTER_DMA_RX_ENABLED == 1)
/* DMA buffer to send the ACK */
static uint16_t ack_buf[1];
static uint16_t nack_buf[1];
#endif

/**********************************************************************************************************************
* API IMPLEMENTATION
**********************************************************************************************************************/

/*
 * @brief API to retrieve the version of the I2C_MASTER APP.
 *
 * @return DAVE_APP_VERSION_t Structure containing major version, minor version
 *         and patch version.
 */
DAVE_APP_VERSION_t I2C_MASTER_GetAppVersion(void)
{
  DAVE_APP_VERSION_t version;

  version.major = I2C_MASTER_MAJOR_VERSION;
  version.minor = I2C_MASTER_MINOR_VERSION;
  version.patch = I2C_MASTER_PATCH_VERSION;

  return (version);
}

/* Function to initialize the USIC Channel with GUI configured values.*/
I2C_MASTER_STATUS_t I2C_MASTER_Init(const I2C_MASTER_t *const handle)
{
  I2C_MASTER_STATUS_t status;

  if (handle != NULL)
  {
    /*Initialize the multiplexers required for I2C_MASTER configuration*/
    handle->config->fptr_i2c_config();

    status = I2C_MASTER_STATUS_SUCCESS;
  }
  else
  {
    status = I2C_MASTER_STATUS_FAILURE;
  }
  return (status);
}

/* Function to get flag status of the requested parameter */
uint32_t I2C_MASTER_GetFlagStatus(const I2C_MASTER_t *handle, uint32_t flagtype)
{
  uint32_t status;

  status = XMC_I2C_CH_GetStatusFlag(handle->channel);

  return (status & flagtype);
}

/* Function to clear flag status of the requested parameter */
void I2C_MASTER_ClearFlag(const I2C_MASTER_t *handle, uint32_t flagtype)
{
  XMC_I2C_CH_ClearStatusFlag(handle->channel,flagtype);
}

/* Function to transmit the data to slave device */
I2C_MASTER_STATUS_t I2C_MASTER_Transmit(I2C_MASTER_t *handle, bool send_start, const uint32_t address,
                                        uint8_t *data, const uint32_t size, bool send_stop)
{
  I2C_MASTER_STATUS_t status;

  status = I2C_MASTER_STATUS_BUSY;

  if(handle->config->transmit_mode == I2C_MASTER_TRANSFER_MODE_INTERRUPT)
  {
#if (I2C_MASTER_INTERRUPT_TX_ENABLED == 1)
    status = I2C_MASTER_StartTransmitIRQ(handle, send_start, address, data, size, send_stop);
#endif
  }
  else if(handle->config->transmit_mode == I2C_MASTER_TRANSFER_MODE_DMA)
  {
#if (I2C_MASTER_DMA_TX_ENABLED == 1)
    status = I2C_MASTER_STATUS_UNSUPPORTED_MODE;
#endif
  }
  else
  {
#if (I2C_MASTER_DIRECT_TX_ENABLED == 1)
    status = I2C_MASTER_lStartTransmitPolling(handle, send_start, address, data, size, send_stop);
#endif
  }

  return (status);
} /* end of function */

#if ((I2C_MASTER_INTERRUPT_TX_ENABLED == 1) || (I2C_MASTER_INTERRUPT_RX_ENABLED == 1))
/*
 * Transmit interrupt handler for the APP.
 * This is a common interrupt handling function called for different instances of the APP.
 *
 *  @param  handle I2C_MASTER APP handle pointer of type I2C_MASTER_t*
 *
 *  @return void
 */
void I2C_MASTER_TransmitHandler(I2C_MASTER_t * const handle)
{
  I2C_MASTER_RUNTIME_t * ptr_runtime;
  uint8_t fifo_min;

  ptr_runtime = handle->runtime;
  fifo_min = 0U;

  /* check if any error flag is set */
  if (I2C_MASTER_GetFlagStatus(handle, ((uint32_t)XMC_I2C_CH_STATUS_FLAG_NACK_RECEIVED |
                                        (uint32_t)XMC_I2C_CH_STATUS_FLAG_ARBITRATION_LOST |
                                        (uint32_t)XMC_I2C_CH_STATUS_FLAG_ERROR |
                    (uint32_t)XMC_I2C_CH_STATUS_FLAG_WRONG_TDF_CODE_FOUND)))
  {
    /* Disable the transmit events */
    XMC_USIC_CH_TXFIFO_DisableEvent(handle->channel,(uint32_t)XMC_USIC_CH_TXFIFO_EVENT_CONF_STANDARD);
    XMC_USIC_CH_DisableEvent(handle->channel, (uint32_t)XMC_USIC_CH_EVENT_TRANSMIT_BUFFER);

    I2C_MASTER_ProtocolHandler(handle);
  }
  else
  {
/***********************************************************************************************************************
  Direction = Transmit, Tx FIFO enabled
***********************************************************************************************************************/
  if (ptr_runtime->direction == (uint32_t)I2C_MASTER_DIRECTION_TRANSMIT)
  {
    if (handle->config->txFIFO_size > 0)
    {
      if (ptr_runtime->tx_data_index < ptr_runtime->tx_data_count)
      {
      I2C_MASTER_DisableEvent(handle,(uint32_t)XMC_I2C_CH_EVENT_ACK);
      XMC_USIC_CH_TXFIFO_EnableEvent(handle->channel, (uint32_t)XMC_USIC_CH_TXFIFO_EVENT_CONF_STANDARD);
        /*Fill the transmit FIFO */
        while (I2C_MASTER_IsTXFIFOFull(handle) == false)
        {
          /* transmit each byte till index reaches to the last byte */
          if (ptr_runtime->tx_data_index < ptr_runtime->tx_data_count)
          {
            /* load the FIFO, byte by byte till either FIFO is full or all data is loaded*/
            I2C_MASTER_TransmitByte(handle, (uint8_t)ptr_runtime->tx_data[ptr_runtime->tx_data_index]);
            ptr_runtime->tx_data_index++;
          }
          else
          {
            break;
          }
        } /* end of while */
      }
      else
      {
        /* if index is reached to last byte and "bus acquired" flag is set to true, then issue Send Stop */
      XMC_USIC_CH_TXFIFO_DisableEvent(handle->channel, (uint32_t)XMC_USIC_CH_TXFIFO_EVENT_CONF_STANDARD);
      NVIC_ClearPendingIRQ(handle->config->tx_irqn);

      /*make sure data is transmitted in FIFO*/
        while (!XMC_USIC_CH_TXFIFO_IsEmpty(handle->channel)){}

          if (ptr_runtime->bus_acquired == true)
          {
            I2C_MASTER_lSendStop_JumpTo_TxCallback(handle);
          }
      }
    } /* end of  if(handle->config->txFIFO_size > 0) */
/***********************************************************************************************************************
    Direction = transmit and Tx FIFO disabled
***********************************************************************************************************************/
    else
    {
      /* transmit each byte till the last byte */
      if (ptr_runtime->tx_data_index < ptr_runtime->tx_data_count)
      {
        I2C_MASTER_TransmitByte(handle, ptr_runtime->tx_data[ptr_runtime->tx_data_index]);
        ptr_runtime->tx_data_index++;
      }
      else
      {
        /* if index reaches last byte and bus_acquired flag is set to true, issue send stop */
        if (ptr_runtime->bus_acquired == true)
        {
          I2C_MASTER_lSendStop_JumpTo_TxCallback(handle);
        }
      }
    }
  } /* end of if(ptr_runtime->direction == (uint32_t)I2C_MASTER_DIRECTION_TRANSMIT) */
  else
  {
/***********************************************************************************************************************
  Direction = Receive, Tx, Rx FIFO enabled.
  Minimum FIFO value is calculated by comparing Tx FIFO and Rx FIFO size.
  If Rx FIFO is not enabled, default size of 2 is considered.
***********************************************************************************************************************/
    if (handle->config->txFIFO_size > 0)
    {
      if ((handle->config->rxFIFO_size > 0))
      {
        fifo_min = (uint8_t)calculate_minfifosize(((uint32_t)1 << (uint32_t)handle->config->txFIFO_size),
                                              ((uint32_t)1 << (uint32_t)handle->config->rxFIFO_size));
      }
      else
      {
        /* if Rx FIFO is disabled, set minimum FIFO size as 2 */
        fifo_min = 2U;
      }

      XMC_USIC_CH_TXFIFO_DisableEvent(handle->channel, (uint32_t)XMC_USIC_CH_TXFIFO_EVENT_CONF_STANDARD);

      /* fill the FIFO */
      while (I2C_MASTER_IsTXFIFOFull(handle) == false)
      {
        if (ptr_runtime->tx_data_index < ptr_runtime->tx_data_count)
        {
          /* check for last byte and send_nack is set to true */
          if (((ptr_runtime->tx_data_index + 1U) == ptr_runtime->tx_data_count) && (ptr_runtime->send_nack == true))
          {
            I2C_MASTER_ReceiveNACK(handle);
          }
          else
          {
            I2C_MASTER_ReceiveACK(handle);
          }
          ptr_runtime->tx_data_index++;

          /*if index reaches fifo size - break*/
          if ((ptr_runtime->tx_data_index) >= fifo_min)
          {
            break;
          }
        }
        else
        {
          break;
        }
      } /* end of while */
    } /* end of if(handle->config->txFIFO_size > 0) */
/***********************************************************************************************************************
   Direction = Receive, Tx FIFO disabled
 **********************************************************************************************************************/
    else
    {
      /* check for last byte and send_nack is set to true */
      if (((ptr_runtime->tx_data_index + 1U) == ptr_runtime->tx_data_count) && (ptr_runtime->send_nack == true))
      {
        I2C_MASTER_ReceiveNACK(handle);
      }
      else
      {
        I2C_MASTER_ReceiveACK(handle);
      }
      ptr_runtime->tx_data_index++;
    }

/***********************************************************************************************************************
   If last byte, then disable ACK event
 **********************************************************************************************************************/
     if (handle->runtime->tx_data_index == handle->runtime->tx_data_count)
     {
       I2C_MASTER_DisableEvent(handle,(uint32_t)XMC_I2C_CH_EVENT_ACK);
     }
  } /* end of else */
 } /* end of else */
}

/* Function to issue Send Stop command and jump to callback routine */
static void I2C_MASTER_lSendStop_JumpTo_TxCallback(I2C_MASTER_t *const handle)
{
  I2C_MASTER_RUNTIME_t * ptr_runtime;

  ptr_runtime = handle->runtime;

  I2C_MASTER_DisableEvent(handle,((uint32_t)XMC_I2C_CH_EVENT_ACK ));

  if (ptr_runtime->send_stop == true)
  {
    ptr_runtime->bus_acquired = false;
    I2C_MASTER_SendStop(handle);
  }

  while (XMC_USIC_CH_GetTransmitBufferStatus(handle->channel) == XMC_USIC_CH_TBUF_STATUS_BUSY){}

  /*All data is transmitted*/
  ptr_runtime->tx_busy = false;

  if (handle->config->tx_cbhandler != NULL)
  {
    /*Execute the 'End of transmission' callback function*/
    handle->config->tx_cbhandler();
  }
}
#endif

/***********************************************************************************************************************
 * @brief This function registers the receive request by configuring the I2C_MASTER
 * receive FIFO/Standard buffer (depending on the user configuration). The data
 * is received asynchronously. When the requested number of data bytes are received,
 * optionally, the user configured callback function will be executed. If a callback
 * function is not configured on the APP UI, the user has to poll for the status of
 * rx_busy variable of the APP handle structure.
 *
 * Note: In FIFO mode, FIFO trigger limit should be adjusted manually to
 * read required amount of data from FIFO buffer.
 *
 *
 * @param  I2C_MASTER_t* I2C_MASTER APP handle pointer of type I2C_MASTER_t
 * @param  bool      flag for send_start
 * @param  uint32_t  slave address
 * @param  uint8_t*  Pointer to data array
 * @param  uint32_t  Total no of bytes to be read.
 * @param  bool      flag for send_stop
 * @param  bool      flag for send_nack
 *
 * @return  I2C_MASTER_STATUS_t I2C_MASTER_STATUS_SUCCESS if the request is accepted.
 *                              I2C_MASTER_STATUS_BUSY if a reception is in progress.
 *
 * <i>Imp Note:</i> Return value should be validated by user to ensure that the
 * request is registered.
 *
 *
 **********************************************************************************************************************/
I2C_MASTER_STATUS_t I2C_MASTER_Receive(I2C_MASTER_t *handle, bool send_start, const uint32_t address, uint8_t * data,
                                   const uint32_t count, bool send_stop, bool send_nack)
{
  I2C_MASTER_STATUS_t status;

  status = I2C_MASTER_STATUS_BUSY;

  if (handle->config->receive_mode == I2C_MASTER_TRANSFER_MODE_INTERRUPT)
  {
#if (I2C_MASTER_INTERRUPT_RX_ENABLED == 1)
  status = I2C_MASTER_StartReceiveIRQ(handle, send_start, address, data, count, send_stop, send_nack);
#endif
  }
  else if (handle->config->receive_mode == I2C_MASTER_TRANSFER_MODE_DMA)
  {
#if (I2C_MASTER_DMA_RX_ENABLED == 1)
  status = I2C_MASTER_STATUS_UNSUPPORTED_MODE;
#endif
  }
  else
  {
#if (I2C_MASTER_DIRECT_RX_ENABLED == 1)
    status = I2C_MASTER_lStartReceivePolling(handle, send_start, address, data, count, send_stop, send_nack);
#endif
  }

  return (status);
}

#if (I2C_MASTER_INTERRUPT_RX_ENABLED == 1)
/***********************************************************************************************************************
     Rx FIFO data
***********************************************************************************************************************/
static void I2C_MASTER_lReceive_FIFOData(I2C_MASTER_t * const handle, bool send_start, const uint32_t address,
                                     const uint32_t count)
{
  I2C_MASTER_RUNTIME_t * ptr_runtime;

  ptr_runtime = handle->runtime;

  /*Clear the receive FIFO, configure the trigger lime
   * and enable the receive events*/
  XMC_USIC_CH_RXFIFO_Flush(handle->channel);

  /*Configure the FIFO trigger limit based on the required data size*/
  I2C_MASTER_lReconfigureRxFIFO(handle, count);

  XMC_USIC_CH_RXFIFO_EnableEvent(handle->channel,
                                (uint32_t)((uint32_t)XMC_USIC_CH_RXFIFO_EVENT_CONF_STANDARD |
                                           (uint32_t)XMC_USIC_CH_RXFIFO_EVENT_CONF_ALTERNATE));
  if (send_start == true)
  {
  if(!((handle->config->transmit_mode == I2C_MASTER_TRANSFER_MODE_DMA) ||
     (handle->config->transmit_mode == I2C_MASTER_TRANSFER_MODE_DIRECT)))
  {
    I2C_MASTER_EnableEvent(handle, (uint32_t)XMC_I2C_CH_EVENT_ACK);
    XMC_I2C_CH_SetInterruptNodePointer(handle->channel,ptr_runtime->tx_ack_sr);
  }
    I2C_MASTER_lSendStart_Or_RepeatedStart(handle,address, (XMC_I2C_CH_CMD_t)XMC_I2C_CH_CMD_READ);

#if (I2C_MASTER_DMA_TX_ENABLED)
    if(handle->config->transmit_mode == I2C_MASTER_TRANSFER_MODE_DMA)
    {
    if (((ptr_runtime->tx_data_index + 1U) == ptr_runtime->tx_data_count) && (ptr_runtime->send_nack == true))
    {
    I2C_MASTER_ReceiveNACK(handle);
    }
    else
    {
    I2C_MASTER_ReceiveACK(handle);
    }
    ptr_runtime->tx_data_index++;
    }
#endif
    if (handle->config->transmit_mode == I2C_MASTER_TRANSFER_MODE_DIRECT)
    {
      if (handle->config->txFIFO_size != XMC_USIC_CH_FIFO_DISABLED)
      {
    /*Fill the transmit FIFO */
      while (I2C_MASTER_IsTXFIFOFull(handle) == false)
      {
        if (ptr_runtime->tx_data_index < ptr_runtime->tx_data_count)
      {
        if (((ptr_runtime->tx_data_index + 1U) == ptr_runtime->tx_data_count) && (ptr_runtime->send_nack == true))
      {
          I2C_MASTER_ReceiveNACK(handle);
      }
      else
        {
          I2C_MASTER_ReceiveACK(handle);
        }
      ptr_runtime->tx_data_index++;
      }
      else
      {
        break;
      }
    } /* end of while */
      }
      else
      {
        /* if it is last byte and send_nack true */
      if (((ptr_runtime->tx_data_index + 1U) == ptr_runtime->tx_data_count) && (ptr_runtime->send_nack == true))
    {
      I2C_MASTER_ReceiveNACK(handle);
    }
    else
    {
      I2C_MASTER_ReceiveACK(handle);
    }
    ptr_runtime->tx_data_index++;
      }
    } /* end of if (handle->config->transmit_mode == I2C_MASTER_TRANSFER_MODE_DIRECT) */
  } /* end of if (send_start == true) */
  else
  {
    /* if Tx FIFO enabled */
    if (handle->config->txFIFO_size > 0)
    {
      XMC_USIC_CH_TXFIFO_DisableEvent(handle->channel,
                                     (uint32_t)XMC_USIC_CH_TXFIFO_EVENT_CONF_STANDARD);
      /*Fill the transmit FIFO */
      while (I2C_MASTER_IsTXFIFOFull(handle) == false)
      {
        if (ptr_runtime->tx_data_index < ptr_runtime->tx_data_count)
        {
          if (((ptr_runtime->tx_data_index + 1U) == ptr_runtime->tx_data_count) &&
               (ptr_runtime->send_nack == true))
          {
            I2C_MASTER_ReceiveNACK(handle);
          }
          else
          {
            I2C_MASTER_ReceiveACK(handle);
          }
          ptr_runtime->tx_data_index++;
        }
        else
        {
          break;
        }
      } /* end of while */
    }
    else  /* Tx FIFO disabled and Rx FIFO enabled */
    {
      if (ptr_runtime->tx_data_index < ptr_runtime->tx_data_count)
      {
        if (((ptr_runtime->tx_data_index + 1U) == ptr_runtime->tx_data_count) &&
             (ptr_runtime->send_nack == true))
        {
          I2C_MASTER_ReceiveNACK(handle);
        }
        else
        {
          XMC_I2C_CH_ClearStatusFlag(handle->channel, ((uint32_t)XMC_I2C_CH_STATUS_FLAG_ACK_RECEIVED |
                                              (uint32_t)XMC_I2C_CH_STATUS_FLAG_TRANSMIT_BUFFER_INDICATION |
                          (uint32_t)XMC_I2C_CH_STATUS_FLAG_TRANSMIT_SHIFT_INDICATION|
                                              (uint32_t)XMC_I2C_CH_STATUS_FLAG_RECEIVE_INDICATION |
                          (uint32_t)XMC_I2C_CH_STATUS_FLAG_ALTERNATIVE_RECEIVE_INDICATION));
          I2C_MASTER_ReceiveACK(handle);
        }
        ptr_runtime->tx_data_index++;
      }
    } /* end of else */
   } /* end of  if(send_start == false) */
}
/***********************************************************************************************************************
    Standard receive mode
***********************************************************************************************************************/
static void I2C_MASTER_lReceive_StdData(I2C_MASTER_t * const handle, bool send_start, const uint32_t address)
{
  I2C_MASTER_RUNTIME_t * ptr_runtime;

  ptr_runtime = handle->runtime;

  XMC_USIC_CH_EnableEvent(handle->channel, (uint32_t)((uint32_t)XMC_USIC_CH_EVENT_STANDARD_RECEIVE |
                                                      (uint32_t)XMC_USIC_CH_EVENT_ALTERNATIVE_RECEIVE));

  if (send_start == true)
  {
  if(!((handle->config->transmit_mode == I2C_MASTER_TRANSFER_MODE_DMA) ||
     (handle->config->transmit_mode == I2C_MASTER_TRANSFER_MODE_DIRECT)))
  {
    I2C_MASTER_EnableEvent(handle, (uint32_t)XMC_I2C_CH_EVENT_ACK);
    XMC_I2C_CH_SetInterruptNodePointer(handle->channel,ptr_runtime->tx_ack_sr);
  }
    I2C_MASTER_lSendStart_Or_RepeatedStart(handle, address, (XMC_I2C_CH_CMD_t)XMC_I2C_CH_CMD_READ);

    if ((handle->config->transmit_mode == I2C_MASTER_TRANSFER_MODE_DMA) ||
        (handle->config->transmit_mode == I2C_MASTER_TRANSFER_MODE_DIRECT))
  {
    if (((ptr_runtime->tx_data_index + 1U) == ptr_runtime->tx_data_count) && (ptr_runtime->send_nack == true))
    {
        I2C_MASTER_ReceiveNACK(handle);
    }
    else
    {
    I2C_MASTER_ReceiveACK(handle);
      }
    ptr_runtime->tx_data_index++;
  }
  }
  else
  {
/***********************************************************************************************************************
     send_start flag is set to false and Tx FIFO is disabled
***********************************************************************************************************************/
    if (handle->config->txFIFO_size == 0)
    {
      if (((ptr_runtime->tx_data_index + 1U) == ptr_runtime->tx_data_count) && (ptr_runtime->send_nack == true))
      {
        I2C_MASTER_ReceiveNACK(handle);
      }
      else
      {
        I2C_MASTER_ReceiveACK(handle);
      }

      ptr_runtime->tx_data_index++;
    }
/***********************************************************************************************************************
     send_start flag is set to false and Tx FIFO is enabled
***********************************************************************************************************************/
    else
    {
      XMC_USIC_CH_TXFIFO_DisableEvent(handle->channel,(uint32_t)XMC_USIC_CH_TXFIFO_EVENT_CONF_STANDARD);

      /*Fill the transmit FIFO */
      while (I2C_MASTER_IsTXFIFOFull(handle) == false)
      {
        if (ptr_runtime->tx_data_index < ptr_runtime->tx_data_count)
        {
          if (((ptr_runtime->tx_data_index + 1U) == ptr_runtime->tx_data_count) && (ptr_runtime->send_nack == true))
          {
            I2C_MASTER_ReceiveNACK(handle);
          }
          else
          {
            I2C_MASTER_ReceiveACK(handle);
          }
          ptr_runtime->tx_data_index++;
        }
        else
        {
          break;
        }
      } /* end of while */
    } /* end of else */
  } /* end of else */
} /* end of function */
#endif

#if ((I2C_MASTER_INTERRUPT_TX_ENABLED == 1) || (I2C_MASTER_INTERRUPT_RX_ENABLED == 1) || \
    (I2C_MASTER_DIRECT_TX_ENABLED == 1) || (I2C_MASTER_DIRECT_RX_ENABLED == 1))
/* Function to issue Send Start/Repeated Start command */
static void I2C_MASTER_lSendStart_Or_RepeatedStart(I2C_MASTER_t * handle,const uint32_t address,
                                               const XMC_I2C_CH_CMD_t cmd)
{
  if (handle->runtime->bus_acquired == true)
  {
  I2C_MASTER_SendRepeatedStart(handle, (uint16_t)address, cmd);
  }
  else
  {
    handle->runtime->bus_acquired = true;
    I2C_MASTER_SendStart(handle, (uint16_t)address, cmd);
  }
}
#endif

#if (I2C_MASTER_INTERRUPT_TX_ENABLED == 1)
I2C_MASTER_STATUS_t I2C_MASTER_StartTransmitIRQ(I2C_MASTER_t *handle, bool send_start, const uint32_t address,
                                                uint8_t *data, const uint32_t size, bool send_stop)
{
  I2C_MASTER_STATUS_t status;
  I2C_MASTER_RUNTIME_t * ptr_runtime;

  status = I2C_MASTER_STATUS_BUSY;
  ptr_runtime = handle->runtime;

  /* If send_stop is set to TRUE, bus_acquired flag is set to FALSE.
   If send_start is set to FALSE and bus_acquired is set to FALSE then API will return an error. */
  if (((send_start == false) && (handle->runtime->bus_acquired == false)) || (data == NULL) || (size == 0U))
  {
  status = I2C_MASTER_STATUS_FAILURE;
  }
  else
  {
    ptr_runtime->direction = (uint32_t)I2C_MASTER_DIRECTION_TRANSMIT;

    if (ptr_runtime->tx_busy == false)
    {
    /*If there is no transmission in progress, obtain the address of data, size of data*/
    ptr_runtime->tx_data = data;
    ptr_runtime->tx_data_count = size;

    /*Initialize to first index and set the busy flag*/
    ptr_runtime->tx_data_index = 0U;
    ptr_runtime->tx_busy = true;
    ptr_runtime->send_stop = send_stop;

    /* Enable ACK event */
    I2C_MASTER_EnableEvent(handle, (uint32_t)XMC_I2C_CH_EVENT_ACK);
    XMC_I2C_CH_SetInterruptNodePointer(handle->channel,ptr_runtime->tx_ack_sr);

    if (send_start == true)
    {
      I2C_MASTER_lSendStart_Or_RepeatedStart(handle, address, (XMC_I2C_CH_CMD_t)XMC_I2C_CH_CMD_WRITE);
    }
    else
    {
      /*Trigger the Ack interrupt*/
      XMC_USIC_CH_TriggerServiceRequest(handle->channel, (uint32_t)ptr_runtime->tx_ack_sr);
    }

    status = I2C_MASTER_STATUS_SUCCESS;
  }
  }
  return (status);
}

static void I2C_MASTER_AbortTransmitIRQ(const I2C_MASTER_t *const handle)
{
  handle->runtime->tx_busy = false;
  handle->runtime->tx_data = NULL;
  handle->runtime->bus_acquired = false;

  /*Disable the transmit interrupts*/
  if (handle->config->txFIFO_size != XMC_USIC_CH_FIFO_DISABLED)
  {
    /*Disable the transmit FIFO event*/
    XMC_USIC_CH_TXFIFO_DisableEvent(handle->channel,(uint32_t)XMC_USIC_CH_TXFIFO_EVENT_CONF_STANDARD);
    XMC_USIC_CH_TXFIFO_Flush(handle->channel);
  }
  I2C_MASTER_DisableEvent((I2C_MASTER_t *)handle,((uint32_t)XMC_I2C_CH_EVENT_ACK ));
}
#endif

#if (I2C_MASTER_INTERRUPT_RX_ENABLED == 1)
I2C_MASTER_STATUS_t I2C_MASTER_StartReceiveIRQ(I2C_MASTER_t *handle, bool send_start, const uint32_t address,
                                               uint8_t * data, const uint32_t count, bool send_stop, bool send_nack)
{
  I2C_MASTER_STATUS_t status;
  I2C_MASTER_RUNTIME_t * ptr_runtime;

  status = I2C_MASTER_STATUS_BUSY;
  ptr_runtime = handle->runtime;

  if (((handle == NULL) || ((send_start == false) && (handle->runtime->bus_acquired == false)) || (data == NULL) ||
     (count == 0U)))
  {
    status = I2C_MASTER_STATUS_FAILURE;
  }
  else
  {
    if (ptr_runtime->rx_busy == false)
    {
    ptr_runtime->direction = (uint32_t)I2C_MASTER_DIRECTION_RECEIVE;

      /* If no active reception in progress, obtain the address of data buffer and number of data bytes to be received*/
    ptr_runtime->rx_data = data;
    ptr_runtime->rx_data_count = count;
    ptr_runtime->tx_data = data;
    ptr_runtime->tx_data_count = count;
    ptr_runtime->tx_busy = true;
    ptr_runtime->rx_busy = true;
    ptr_runtime->send_stop = send_stop;
    ptr_runtime->send_nack = send_nack;
    ptr_runtime->rx_data_index = 0U;
    ptr_runtime->tx_data_index = 0U;

    if (handle->config->rxFIFO_size > 0)
    {
      I2C_MASTER_lReceive_FIFOData(handle, send_start, address, count);
    }
    else
    {
      I2C_MASTER_lReceive_StdData(handle, send_start, address);
    }
    status = I2C_MASTER_STATUS_SUCCESS;
  }
  }
  return (status);
}

/*
 * Receive interrupt handler for the APP.
 * This is a common interrupt handling function for different instances of the I2C_MASTER APP.
 *
 * @param  handle I2C_MASTER APP handle pointer of type I2C_MASTER_t*
 *
 * @return void
 */
void I2C_MASTER_ReceiveHandler(I2C_MASTER_t * const handle)
{
  I2C_MASTER_RUNTIME_t * ptr_runtime;
  uint8_t fifo_lindex;
  uint8_t fifo_min;

  ptr_runtime = handle->runtime;
  fifo_lindex = 0U;

  if (ptr_runtime->rx_busy == true)
  {
    if (handle->config->rxFIFO_size > 0)
    {
      /*****************************************************************************************************************
       Rx FIFO enabled
      *****************************************************************************************************************/
      while (I2C_MASTER_IsRXFIFOEmpty(handle) == false)
      {
        /*Read all the content of Receive FIFO */
        ptr_runtime->rx_data[ptr_runtime->rx_data_index] = (uint8_t)I2C_MASTER_GetReceivedByte(handle);
        ptr_runtime->rx_data_index++;

        if (ptr_runtime->rx_data_index == ptr_runtime->rx_data_count)
        {
          /*Reception complete*/
          ptr_runtime->rx_busy = false;

            /*Disable both standard receive and alternative receive FIFO events*/
            XMC_USIC_CH_RXFIFO_DisableEvent(handle->channel,
                                          (uint32_t)((uint32_t)XMC_USIC_CH_RXFIFO_EVENT_CONF_STANDARD |
                                                     (uint32_t)XMC_USIC_CH_RXFIFO_EVENT_CONF_ALTERNATE));

          break;
        }
      } /* end of while(I2C_MASTER_IsRXFIFOEmpty(handle) == false)*/

      /*Set the trigger limit if data still to be received*/
      if (ptr_runtime->rx_data_index < ptr_runtime->rx_data_count)
      {
        I2C_MASTER_lReconfigureRxFIFO(handle,(uint32_t)(ptr_runtime->rx_data_count - ptr_runtime->rx_data_index));

        if ((handle->config->txFIFO_size > 0))
        {
          fifo_min = (uint8_t)calculate_minfifosize(((uint32_t)1 << (uint32_t)handle->config->txFIFO_size),
                                                    ((uint32_t)1 << (uint32_t)handle->config->rxFIFO_size));
       }
       else
       {
          fifo_min = 2U;
       }
       /****************************************************************************************************************
         Rx and Tx FIFO enabled
        ***************************************************************************************************************/
        if (handle->config->txFIFO_size > 0)
        {
          /*Fill the transmit FIFO */
          while (I2C_MASTER_IsTXFIFOFull(handle) == false)
          {
            if (ptr_runtime->tx_data_index < ptr_runtime->tx_data_count)
            {
              if (((ptr_runtime->tx_data_index + 1U) == ptr_runtime->tx_data_count) && (ptr_runtime->send_nack == true))
              {
                I2C_MASTER_ReceiveNACK(handle);
              }
              else
              {
                I2C_MASTER_ReceiveACK(handle);
              }
              ptr_runtime->tx_data_index++;

              /* if fifo size- break */
              if ((++fifo_lindex) >= fifo_min)
              {
                fifo_lindex = 0U;
                break;
              }
            }/* end of if(handle->runtime->tx_data_index < handle->runtime->tx_data_count) */
            else
            {
              break;
            }
         }
       } /* end of  if((handle->config->txFIFO_size > 0)) */
       /****************************************************************************************************************
          Rx FIFO is enabled, Tx FIFO disabled
       ****************************************************************************************************************/
       else
       {
         if (((ptr_runtime->tx_data_index + 1U) == ptr_runtime->tx_data_count) && (ptr_runtime->send_nack == true))
         {
           I2C_MASTER_ReceiveNACK(handle);
         }
         else
         {
           I2C_MASTER_ReceiveACK(handle);
         }

         ptr_runtime->tx_data_index++;
       }
     } /* end of if(ptr_runtime->rx_data_index < ptr_runtime->rx_data_count) */
/***********************************************************************************************************************
     if last byte to receive then disable receive events and jump to callback routine
***********************************************************************************************************************/
     if (ptr_runtime->rx_data_index == ptr_runtime->rx_data_count)
     {
       /*Clear both standard receive and alternative receive FIFO events*/
       XMC_USIC_CH_RXFIFO_DisableEvent(handle->channel, (uint32_t)((uint32_t)XMC_USIC_CH_RXFIFO_EVENT_CONF_STANDARD |
                                                                   (uint32_t)XMC_USIC_CH_RXFIFO_EVENT_CONF_ALTERNATE));

       /*Disable both standard receive and alternative receive events*/
       XMC_USIC_CH_DisableEvent(handle->channel, (uint32_t)((uint32_t)XMC_USIC_CH_EVENT_ALTERNATIVE_RECEIVE |
                                                            (uint32_t)XMC_USIC_CH_EVENT_STANDARD_RECEIVE));

       if (ptr_runtime->bus_acquired == true)
       {
         I2C_MASTER_lSendStop_JumpTo_RxCallback(handle);
       }
     }
    } /*  end of if(handle->config->rxFIFO_size > 0) */
/***********************************************************************************************************************
     Rx FIFO disabled
***********************************************************************************************************************/
    else
    {
      ptr_runtime->rx_data[ptr_runtime->rx_data_index] = (uint8_t)I2C_MASTER_GetReceivedByte(handle);
      ptr_runtime->rx_data_index++;

      if (ptr_runtime->rx_data_index < ptr_runtime->rx_data_count)
      {
        if (ptr_runtime->tx_data_index < ptr_runtime->tx_data_count)
        {
          /* if receive byte is end of byte and send_nack is true, send to receive Nack otherwise Ack*/
          if (((ptr_runtime->tx_data_index) == (ptr_runtime->tx_data_count - 1U)) && (ptr_runtime->send_nack == true))
          {
            I2C_MASTER_ReceiveNACK(handle);
          }
          else
          {
            I2C_MASTER_ReceiveACK(handle);
          }
          ptr_runtime->tx_data_index++;
        }
      }
      else
      {
        /*Disable both standard receive and alternative receive events*/
        XMC_USIC_CH_DisableEvent(handle->channel, (uint32_t)((uint32_t)XMC_USIC_CH_EVENT_ALTERNATIVE_RECEIVE |
                                                             (uint32_t)XMC_USIC_CH_EVENT_STANDARD_RECEIVE));
        if (ptr_runtime->bus_acquired == true)
        {
          I2C_MASTER_lSendStop_JumpTo_RxCallback(handle);
        }
      }
    }
  } /* end of  if(ptr_runtime->rx_busy == true)*/
}

/* Function to issue Send Stop command and jump to receive callback routine */
static void I2C_MASTER_lSendStop_JumpTo_RxCallback(I2C_MASTER_t *const handle)
{
  I2C_MASTER_RUNTIME_t * ptr_runtime;

  ptr_runtime = handle->runtime;

  if (ptr_runtime->send_stop == true)
  {
    while (XMC_USIC_CH_GetTransmitBufferStatus(handle->channel) == XMC_USIC_CH_TBUF_STATUS_BUSY){}

    ptr_runtime->bus_acquired = false;

    I2C_MASTER_SendStop(handle);
  }

  while (XMC_USIC_CH_GetTransmitBufferStatus(handle->channel) == XMC_USIC_CH_TBUF_STATUS_BUSY){}

  /* Reception complete */
  ptr_runtime->rx_busy = false;
  ptr_runtime->tx_busy = false;

  if (handle->config->rx_cbhandler != NULL)
  {
    /*Execute the 'End of reception' callback function*/
    handle->config->rx_cbhandler();
  }
}


static void I2C_MASTER_lAbortReceiveIRQ(const I2C_MASTER_t *const handle)
{
  /* Reset the user buffer pointer to null */
  handle->runtime->rx_busy = false;
  handle->runtime->tx_busy = false;
  handle->runtime->rx_data = NULL;

  handle->runtime->bus_acquired = false;

  /* Disable the receive interrupts */
  if (handle->config->rxFIFO_size != XMC_USIC_CH_FIFO_DISABLED)
  {
    XMC_USIC_CH_RXFIFO_DisableEvent(handle->channel, (uint32_t)((uint32_t)XMC_USIC_CH_RXFIFO_EVENT_CONF_STANDARD |
                                                    (uint32_t)XMC_USIC_CH_RXFIFO_EVENT_CONF_ALTERNATE));
  }
  else
  {
    XMC_USIC_CH_DisableEvent(handle->channel, (uint32_t)((uint32_t)XMC_USIC_CH_EVENT_STANDARD_RECEIVE |
                                                 (uint32_t)XMC_USIC_CH_EVENT_ALTERNATIVE_RECEIVE));
  }
  I2C_MASTER_DisableEvent((I2C_MASTER_t *)handle,((uint32_t)XMC_I2C_CH_EVENT_ACK ));
}
#endif

/*
 * Protocol interrupt handling function.
 * The function is common for different instances of the I2C_MASTER APP.
 *
 * @param  handle I2C_MASTER APP handle pointer of type I2C_MASTER_t*
 *
 * @return void
 */
void I2C_MASTER_ProtocolHandler(I2C_MASTER_t * const handle)
{
  uint32_t psr_status;

  psr_status = XMC_I2C_CH_GetStatusFlag(handle->channel);

  /* Check for nack event */
  if ((handle->config->nack_cbhandler != NULL) && (psr_status & (uint32_t)XMC_I2C_CH_STATUS_FLAG_NACK_RECEIVED))
  {
    I2C_MASTER_ClearFlag(handle,(uint32_t)XMC_I2C_CH_STATUS_FLAG_NACK_RECEIVED);
    handle->config->nack_cbhandler();
  }

  /* Check for arbitration lost */
  if ((handle->config->arbitration_cbhandler != NULL) && (psr_status & (uint32_t)XMC_I2C_CH_STATUS_FLAG_ARBITRATION_LOST))
  {
    I2C_MASTER_ClearFlag(handle,(uint32_t)XMC_I2C_CH_STATUS_FLAG_ARBITRATION_LOST);
    handle->config->arbitration_cbhandler();
  }

  /* Check for error detected */
  if ((handle->config->error_cbhandler != NULL) && (psr_status & ((uint32_t)XMC_I2C_CH_STATUS_FLAG_ERROR | (uint32_t)XMC_I2C_CH_STATUS_FLAG_WRONG_TDF_CODE_FOUND)))
  {
    I2C_MASTER_ClearFlag(handle,(uint32_t)XMC_I2C_CH_STATUS_FLAG_ERROR);
    handle->config->error_cbhandler();
  }
}

#if (I2C_MASTER_INTERRUPT_RX_ENABLED == 1)
/*
 * @brief A local function to reconfigure Receive FIFO with the given size and trigger limit.
 * Size is needed because the FIFO should be disabled before changing the trigger limit by
 * clearing the FIFO size.
 *
 * @param I2C_MASTER_t * pointer to the I2C_MASTER APP handle
 * @param uint32_t  number of bytes to be received.
 *
 * @return void.
 */

static void I2C_MASTER_lReconfigureRxFIFO(const I2C_MASTER_t * const handle, uint32_t data_size)
{
  uint32_t minfifo_value;
  uint8_t tx_fifo_size;
  uint8_t rx_fifo_size;
  uint8_t fifo_limit;

  rx_fifo_size = (uint8_t)((uint8_t)1 << handle->config->rxFIFO_size);

  if ((handle->config->txFIFO_size > 0))
  {
    tx_fifo_size = (uint8_t)((uint8_t)1 << handle->config->txFIFO_size);
  }
  else
  {
    tx_fifo_size = 1U;
  }

  minfifo_value = (uint32_t)(calculate_minfifosize((uint32_t)tx_fifo_size, (uint32_t)rx_fifo_size));

  fifo_limit = (uint8_t)(calculate_minfifosize(data_size, minfifo_value));

  /* Set the limit value */
  I2C_MASTER_SetRXFIFOTriggerLimit((I2C_MASTER_t *)handle, handle->config->rxFIFO_size, ((uint32_t)fifo_limit - 1U));
}
#endif

/***********************************************************************************************************************
 * @brief Aborts the ongoing data transmission.
 * @param I2C_MASTER_t*  I2C_MASTER APP handle pointer of type I2C_MASTER_t
 * @return I2C_MASTER_STATUS_t
 *
 * Details of function:
 * If there is a transmission in progress, it will be stopped. If transmit FIFO is used,
 * the existing data will be flushed. After the transmission is stopped, user can start
 * a new transmission without delay.
 **********************************************************************************************************************/
I2C_MASTER_STATUS_t I2C_MASTER_AbortTransmit(const I2C_MASTER_t *const handle)
{
  I2C_MASTER_STATUS_t status;

  status = I2C_MASTER_STATUS_SUCCESS;

  if (handle->config->transmit_mode == I2C_MASTER_TRANSFER_MODE_INTERRUPT)
  {
#if (I2C_MASTER_INTERRUPT_TX_ENABLED == 1)
    I2C_MASTER_AbortTransmitIRQ(handle);
#endif
  }
  else if (handle->config->transmit_mode == I2C_MASTER_TRANSFER_MODE_DMA)
  {
#if (I2C_MASTER_DMA_TX_ENABLED == 1)
    I2C_MASTER_lAbortTransmitDMA(handle);
#endif
  }
  else
  {
    status = I2C_MASTER_STATUS_FAILURE;
  }
  handle->channel->PSCR |= USIC_CH_PSR_IICMode_WTDF_Msk; /*clear WDTF*/
  handle->channel->FMR = 0x00000002U;/*clear TDV*/

  return (status);
}

/***********************************************************************************************************************
 * @brief Aborts the ongoing data reception.
 * @param I2C_MASTER_t* I2C_MASTER APP handle pointer of type I2C_MASTER_t
 * @return I2C_MASTER_STATUS_t
 *
 * Details of function:
 * If a reception is in progress, it will be stopped. When a reception request
 * is active, user will not be able to place a new receive request till the active
 * reception is complete. This API can stop the progressing reception to make
 * a new receive request.
 **********************************************************************************************************************/
I2C_MASTER_STATUS_t I2C_MASTER_AbortReceive(const I2C_MASTER_t *const handle)
{
  I2C_MASTER_STATUS_t status;

  status = I2C_MASTER_STATUS_SUCCESS;

  if (handle->config->receive_mode == I2C_MASTER_TRANSFER_MODE_INTERRUPT)
  {
#if (I2C_MASTER_INTERRUPT_RX_ENABLED == 1)
    I2C_MASTER_lAbortReceiveIRQ(handle);
#endif
  }
  else if (handle->config->receive_mode == I2C_MASTER_TRANSFER_MODE_DMA)
  {
#if (I2C_MASTER_DMA_RX_ENABLED == 1)
    I2C_MASTER_lAbortReceiveDMA(handle);
#endif
  }
  else
  {
    status = I2C_MASTER_STATUS_FAILURE;
  }

  return (status);
}

#if (I2C_MASTER_DMA_RX_ENABLED == 1)
I2C_MASTER_STATUS_t I2C_MASTER_StartReceiveDMA(const I2C_MASTER_t *const handle, uint32_t data_count, uint8_t *addr)
{
  I2C_MASTER_STATUS_t status;
  const I2C_MASTER_DMA_CONFIG_t *rx_dma_config;
  const GLOBAL_DMA_t *rx_dma_config_global;

#if (I2C_MASTER_DMA_TX_ENABLED == 1)
  const I2C_MASTER_DMA_CONFIG_t *tx_dma_config;
  const GLOBAL_DMA_t *tx_dma_config_global;
  uint8_t tx_ch_num;
  tx_ch_num = 0U;
  tx_dma_config = handle->config->transmit_dma_config;
  tx_dma_config_global = handle->config->transmit_dma_config->global_dma;
#endif

  status = I2C_MASTER_STATUS_BUSY;
  rx_dma_config = handle->config->receive_dma_config;
  rx_dma_config_global = handle->config->receive_dma_config->global_dma;
  
  if ((addr == NULL) || (data_count > I2C_DMA_MAX_BLOCK_SIZE) || (data_count == 0U))
  {
    status = I2C_MASTER_STATUS_FAILURE;
  }
  else
  {
    if (handle->runtime->rx_busy == false)
    {
      handle->runtime->rx_busy = true;
    I2C_MASTER_DisableEvent((I2C_MASTER_t *)handle, (uint32_t)XMC_I2C_CH_EVENT_ACK);
    handle->runtime->rx_dma_data_count = data_count;

    XMC_USIC_CH_EnableEvent(handle->channel, ((uint32_t)XMC_USIC_CH_EVENT_STANDARD_RECEIVE |
                                              (uint32_t)XMC_USIC_CH_EVENT_ALTERNATIVE_RECEIVE));
#if (I2C_MASTER_DMA_TX_ENABLED == 1)
    XMC_DMA_CH_SetBlockSize(rx_dma_config_global->dma, rx_dma_config->dma_channel, data_count);
#else
    XMC_DMA_CH_SetBlockSize(rx_dma_config_global->dma, rx_dma_config->dma_channel, 1);
#endif
    XMC_DMA_CH_SetSourceAddress(rx_dma_config_global->dma, rx_dma_config->dma_channel, (uint32_t)&handle->channel->RBUF);
    XMC_DMA_CH_SetDestinationAddress(rx_dma_config_global->dma, rx_dma_config->dma_channel, (uint32_t)addr);

    if (handle->config->transmit_mode == I2C_MASTER_TRANSFER_MODE_DMA)
    {
#if (I2C_MASTER_DMA_TX_ENABLED == 1)
    /* ACK TDF value */
      ack_buf[0] = (uint16_t)I2C_MASTER_TDF_RECEIVE_ACK;
      nack_buf[0] = (uint16_t)I2C_MASTER_TDF_RECEIVE_NACK;
    handle->runtime->direction = (uint32_t)I2C_MASTER_DIRECTION_RECEIVE;
    /* need to make source reload for tx, transfer width for tx= 2 bytes */
    tx_ch_num = handle->config->transmit_dma_config->dma_channel;
    /* clear the bits */
    tx_dma_config_global->dma->CH[tx_ch_num].CTLL &= ~((uint32_t)I2C_MASTER_DMA_SRC_DST_TR_WIDTH_MASK |
                                                        (uint32_t)I2C_MASTER_DMA_SRC_ADDR_INC_MASK);

    /* set the src and dest transf width as XMC_DMA_CH_TRANSFER_WIDTH_16 */
    tx_dma_config_global->dma->CH[tx_ch_num].CTLL |= (((uint32_t)XMC_DMA_CH_TRANSFER_WIDTH_16 <<
                                                        (uint32_t)I2C_MASTER_DMA_DST_TRANSFER_WIDTH_POS) |
                                                       ((uint32_t)XMC_DMA_CH_TRANSFER_WIDTH_16 <<
                                                      (uint32_t)I2C_MASTER_DMA_SRC_TRANSFER_WIDTH_POS));

      /* set the tx channel src address inc mode to XMC_DMA_CH_ADDRESS_COUNT_MODE_NO_CHANGE */
    tx_dma_config_global->dma->CH[tx_ch_num].CTLL |= ((uint32_t)XMC_DMA_CH_ADDRESS_COUNT_MODE_NO_CHANGE <<
                                                       (uint32_t)I2C_MASTER_DMA_SRC_ADDR_INC_POS);



      XMC_USIC_CH_EnableEvent(handle->channel, (uint32_t)XMC_USIC_CH_EVENT_RECEIVE_START);



        if(data_count == 1U)
    {
          XMC_DMA_CH_SetSourceAddress(tx_dma_config_global->dma, tx_dma_config->dma_channel, (uint32_t)nack_buf);
          XMC_DMA_CH_SetBlockSize(tx_dma_config_global->dma, tx_dma_config->dma_channel, 1);
    }
        else
        {
          XMC_DMA_CH_SetSourceAddress(tx_dma_config_global->dma, tx_dma_config->dma_channel, (uint32_t)ack_buf);
          XMC_DMA_CH_SetBlockSize(tx_dma_config_global->dma, tx_dma_config->dma_channel, data_count - 1);
        }
        XMC_DMA_CH_SetDestinationAddress(tx_dma_config_global->dma, tx_dma_config->dma_channel,
                                     (uint32_t)&handle->channel->TBUF[0]);




        XMC_DMA_CH_Enable(tx_dma_config_global->dma, tx_dma_config->dma_channel);
#endif
    }
      else
      {
        if (data_count > 1U)
        {
          I2C_MASTER_ReceiveACK((I2C_MASTER_t * const)handle);
        }
        else
        {
      I2C_MASTER_ReceiveNACK((I2C_MASTER_t * const)handle);
    }

    }
    XMC_DMA_CH_Enable(rx_dma_config_global->dma, rx_dma_config->dma_channel);

    status = I2C_MASTER_STATUS_SUCCESS;

    } /* end of if(handle->runtime->rx_busy == false) */
  } /* end of else */

  return (status);
}
/***********************************************************************************************************************
 * @brief Aborts the ongoing data reception.
 * @param I2C_MASTER_t* I2C_MASTER APP handle pointer of type I2C_MASTER_t
 * @return None
 *
 * Details of function:
 * If a reception is in progress, it will be stopped. When a reception request
 * is active, user will not be able to place a new receive request till the active
 * reception is complete. This API can stop the progressing reception to make
 * a new receive request.
 **********************************************************************************************************************/
static void I2C_MASTER_lAbortReceiveDMA(const I2C_MASTER_t *const handle)
{
  const I2C_MASTER_DMA_CONFIG_t *rx_dma_config;
  const GLOBAL_DMA_t *rx_dma_config_global;
#if (I2C_MASTER_DMA_TX_ENABLED == 1)
  const I2C_MASTER_DMA_CONFIG_t *tx_dma_config;
  const GLOBAL_DMA_t *tx_dma_config_global;
#endif

  rx_dma_config = handle->config->receive_dma_config;
  rx_dma_config_global = handle->config->receive_dma_config->global_dma;
#if (I2C_MASTER_DMA_TX_ENABLED == 1)
  tx_dma_config = handle->config->transmit_dma_config;
  tx_dma_config_global = handle->config->transmit_dma_config->global_dma;
#endif

  /* Reset the user buffer pointer to null */
  handle->runtime->rx_busy = false;
  handle->runtime->rx_dma_data_index = 0U;

  if (XMC_DMA_CH_IsEnabled(rx_dma_config_global->dma, rx_dma_config->dma_channel))
  {
    XMC_DMA_CH_Disable(rx_dma_config_global->dma, rx_dma_config->dma_channel);
  }
#if (I2C_MASTER_DMA_TX_ENABLED == 1)
  if(handle->config->transmit_mode == I2C_MASTER_TRANSFER_MODE_DMA)
  {
    if (XMC_DMA_CH_IsEnabled(tx_dma_config_global->dma, tx_dma_config->dma_channel))
    {
      XMC_DMA_CH_Disable(tx_dma_config_global->dma, tx_dma_config->dma_channel);
    }
    while (XMC_DMA_CH_IsEnabled(tx_dma_config_global->dma, tx_dma_config->dma_channel) == 1U){}
  }
#endif

  while (XMC_DMA_CH_IsEnabled(rx_dma_config_global->dma, rx_dma_config->dma_channel) == 1U){}


  XMC_USIC_CH_DisableEvent(handle->channel, ((uint32_t)XMC_USIC_CH_EVENT_STANDARD_RECEIVE |
                                             (uint32_t)XMC_USIC_CH_EVENT_ALTERNATIVE_RECEIVE));
}
#endif

#if (I2C_MASTER_DMA_TX_ENABLED == 1)
I2C_MASTER_STATUS_t I2C_MASTER_StartTransmitDMA(const I2C_MASTER_t *const handle, uint32_t block_size, uint8_t *addr)
{
  I2C_MASTER_STATUS_t status;
  const I2C_MASTER_DMA_CONFIG_t *tx_dma_config;
  const GLOBAL_DMA_t *tx_dma_config_global;
  uint8_t tx_ch_num;
 
  status = I2C_MASTER_STATUS_BUSY;
 
  tx_dma_config = handle->config->transmit_dma_config;
  tx_dma_config_global = handle->config->transmit_dma_config->global_dma;
  
  tx_ch_num = 0U;
 
  if ((addr == NULL) || (block_size > I2C_DMA_MAX_BLOCK_SIZE) || (!block_size))
  {
    status = I2C_MASTER_STATUS_FAILURE;
  }
  else
  {
    if (handle->runtime->tx_busy == false)
    {
      tx_ch_num = handle->config->transmit_dma_config->dma_channel;
      /* clear the bits */
      tx_dma_config_global->dma->CH[tx_ch_num].CTLL &= ~((uint32_t)I2C_MASTER_DMA_SRC_DST_TR_WIDTH_MASK | (uint32_t)I2C_MASTER_DMA_SRC_ADDR_INC_MASK);
      /* set the src and dest transf width as XMC_DMA_CH_TRANSFER_WIDTH_8 */
      tx_dma_config_global->dma->CH[tx_ch_num].CTLL |= (((uint32_t)XMC_DMA_CH_TRANSFER_WIDTH_8 << (uint32_t)I2C_MASTER_DMA_DST_TRANSFER_WIDTH_POS) |
                                                        ((uint32_t)XMC_DMA_CH_TRANSFER_WIDTH_8 << (uint32_t)I2C_MASTER_DMA_SRC_TRANSFER_WIDTH_POS));
      /* set the tx channel src address inc mode to XMC_DMA_CH_ADDRESS_COUNT_MODE_INCREMENT */
      tx_dma_config_global->dma->CH[tx_ch_num].CTLL |= ((uint32_t)XMC_DMA_CH_ADDRESS_COUNT_MODE_INCREMENT << (uint32_t)I2C_MASTER_DMA_SRC_ADDR_INC_POS);
 
      XMC_DMA_ClearRequestLine(tx_dma_config_global->dma, handle->config->transmit_dma_config->dma_ch_config->dst_peripheral_request & 0xf);
      I2C_MASTER_EnableEvent((I2C_MASTER_t * const)handle, (uint32_t)XMC_I2C_CH_EVENT_ACK);
 
      handle->runtime->direction = (uint32_t)I2C_MASTER_DIRECTION_TRANSMIT;
      handle->runtime->tx_busy = true;

      XMC_I2C_CH_MasterTransmit(handle->channel,*addr);
      block_size--;
 
      if(block_size)
      {
        XMC_DMA_CH_SetBlockSize(tx_dma_config_global->dma, tx_dma_config->dma_channel, block_size);
        XMC_DMA_CH_SetSourceAddress(tx_dma_config_global->dma, tx_dma_config->dma_channel, (uint32_t)((uint8_t*)addr+1));
        XMC_DMA_CH_SetDestinationAddress(tx_dma_config_global->dma, tx_dma_config->dma_channel, (uint32_t)&handle->channel->TBUF[0]);
 
        XMC_DMA_CH_Enable(tx_dma_config_global->dma, tx_dma_config->dma_channel);
      }
      else
      {
        handle->runtime->tx_busy = false;
        if(handle->config->tx_cbhandler)
        {
          handle->config->tx_cbhandler();
        }
      }

      status = I2C_MASTER_STATUS_SUCCESS;
    }
  }

  return (status);
}

/***********************************************************************************************************************
 * @brief Aborts the ongoing data transmission.
 * @param I2C_MASTER_t*  I2C_MASTER APP handle pointer of type I2C_MASTER_t
 * @return None
 *
 * Details of function:
 * If there is a transmission in progress, it will be stopped. If transmit FIFO is used,
 * the existing data will be flushed. After the transmission is stopped, user can start
 * a new transmission without delay.
 **********************************************************************************************************************/
static void I2C_MASTER_lAbortTransmitDMA(const I2C_MASTER_t *const handle)
{
  const I2C_MASTER_DMA_CONFIG_t *tx_dma_config;
  const GLOBAL_DMA_t *tx_dma_config_global;
  
  tx_dma_config = handle->config->transmit_dma_config;
  tx_dma_config_global = handle->config->transmit_dma_config->global_dma;

  handle->runtime->tx_busy = false;

  if (XMC_DMA_CH_IsEnabled(tx_dma_config_global->dma, tx_dma_config->dma_channel))
  {
    XMC_DMA_CH_Disable(tx_dma_config_global->dma, tx_dma_config->dma_channel);
  }

  while (XMC_DMA_CH_IsEnabled(tx_dma_config_global->dma, tx_dma_config->dma_channel) == 1U){}

  I2C_MASTER_DisableEvent((I2C_MASTER_t *)handle, (uint32_t)XMC_I2C_CH_EVENT_ACK);
}

#endif

#if (I2C_MASTER_DIRECT_TX_ENABLED == 1)
static I2C_MASTER_STATUS_t I2C_MASTER_lStartTransmitPolling(I2C_MASTER_t *const handle, bool send_start,
                                                        const uint32_t slave_address, uint8_t *data,uint32_t size,
                              bool send_stop)
{
  uint32_t buffer_index;
  I2C_MASTER_STATUS_t status;

  status = I2C_MASTER_STATUS_BUSY;

  buffer_index = 0U;

  if ((((send_start == false) && (handle->runtime->bus_acquired == false)) || (data == NULL) || (size == 0U)))
  {
    status = I2C_MASTER_STATUS_FAILURE;
  }
  else
  {
    if (send_start == true)
    {
      if (handle->runtime->bus_acquired == false)
    {
      I2C_MASTER_lSendStart_Or_RepeatedStart(handle, slave_address, XMC_I2C_CH_CMD_WRITE);
    while (I2C_MASTER_GetFlagStatus(handle, (uint32_t)XMC_I2C_CH_STATUS_FLAG_ACK_RECEIVED) == 0U)
    {
      /* wait for ACK */
    }
    I2C_MASTER_ClearFlag(handle, (uint32_t)XMC_I2C_CH_STATUS_FLAG_ACK_RECEIVED);
    }
    }

  if (handle->config->txFIFO_size == XMC_USIC_CH_FIFO_DISABLED)
  {
    /* send data, byte by byte */
    while (buffer_index < size)
    {
    I2C_MASTER_TransmitByte(handle, data[buffer_index]);
    while (I2C_MASTER_GetFlagStatus(handle, (uint32_t)XMC_I2C_CH_STATUS_FLAG_ACK_RECEIVED) == 0U)
    {
      /* wait for ACK */
    }
    I2C_MASTER_ClearFlag(handle, (uint32_t)XMC_I2C_CH_STATUS_FLAG_ACK_RECEIVED);

    buffer_index++;
      }
  }
  else
  {
    while (buffer_index < size)
    {
    /* Fill the transmit FIFO */
    while (I2C_MASTER_IsTXFIFOFull(handle) == false)
    {
      /* transmit each byte till index reaches to the last byte */
      if (buffer_index < size)
      {
        /* load the FIFO, byte by byte till either FIFO is full or all data is loaded*/
      I2C_MASTER_TransmitByte(handle, data[buffer_index]);
      buffer_index++;
      }
      else
      {
        break;
      }
    }
    }
    /*make sure data is transmitted from FIFO*/
    while (!XMC_USIC_CH_TXFIFO_IsEmpty(handle->channel)){}
  }

  if(send_stop == true)
  {
    handle->runtime->bus_acquired = false;
    I2C_MASTER_SendStop(handle);
  }

  status = I2C_MASTER_STATUS_SUCCESS;
  }

  return (status);
}
#endif

#if (I2C_MASTER_DIRECT_RX_ENABLED == 1)
static I2C_MASTER_STATUS_t I2C_MASTER_lStartReceivePolling(I2C_MASTER_t *const handle, bool send_start,
                                                       uint32_t slave_address, uint8_t *data, uint32_t count,
                               bool send_stop, bool send_nack)
{
  I2C_MASTER_STATUS_t status;
  uint32_t buffer_index;
  uint32_t temp_index;

  status = I2C_MASTER_STATUS_BUSY;
  if ((((send_start == false) && (handle->runtime->bus_acquired == false)) || (data == NULL) || (count == 0U)))
  {
    status = I2C_MASTER_STATUS_FAILURE;
  }
  else
  {
  buffer_index = 0U;
  temp_index = 0U;
    if (send_start == true)
    {
      I2C_MASTER_lSendStart_Or_RepeatedStart(handle, slave_address, XMC_I2C_CH_CMD_READ);
      while (I2C_MASTER_GetFlagStatus(handle, (uint32_t)XMC_I2C_CH_STATUS_FLAG_ACK_RECEIVED) == 0U)
    {
      /* wait for ACK */
    }
    I2C_MASTER_ClearFlag(handle, (uint32_t)XMC_I2C_CH_STATUS_FLAG_ACK_RECEIVED);
  }

  if (handle->config->txFIFO_size == XMC_USIC_CH_FIFO_DISABLED)
  {
    while (buffer_index < count)
    {
      if (((buffer_index + 1U) == count) && (send_nack == true))
    {
        I2C_MASTER_ReceiveNACK(handle);
    }
    else
    {
      I2C_MASTER_ReceiveACK(handle);
    }

      while ((I2C_MASTER_GetFlagStatus(handle, (uint32_t)XMC_I2C_CH_STATUS_FLAG_ALTERNATIVE_RECEIVE_INDICATION) == 0U) &&
         (I2C_MASTER_GetFlagStatus(handle, (uint32_t)XMC_I2C_CH_STATUS_FLAG_RECEIVE_INDICATION) == 0U))
    {
      /* wait for RSI */
    }

    I2C_MASTER_ClearFlag(handle, (uint32_t)XMC_I2C_CH_STATUS_FLAG_ALTERNATIVE_RECEIVE_INDICATION);
    I2C_MASTER_ClearFlag(handle, (uint32_t)XMC_I2C_CH_STATUS_FLAG_RECEIVE_INDICATION);

    data[buffer_index++] = I2C_MASTER_GetReceivedByte(handle);
    }
  } /* end of if (handle->config->txFIFO_size == XMC_USIC_CH_FIFO_DISABLED) */
  else
  {
    temp_index = buffer_index;
    while (temp_index < count)
    {
      while (I2C_MASTER_IsTXFIFOFull(handle) == false)
    {
      /* transmit each byte till index reaches to the last byte */
      if (temp_index < count)
      {
        /* load the FIFO, byte by byte till either FIFO is full or all data is loaded*/
        if (((temp_index + 1U) == count) && (send_nack == true))
      {
        I2C_MASTER_ReceiveNACK(handle);
      }
            else
      {
        I2C_MASTER_ReceiveACK(handle);
      }
      temp_index++;
      }
      else
      {
        break;
      }
    } /* end of while (I2C_MASTER_IsTXFIFOFull(handle) == false) */

    while (buffer_index < temp_index)
    {
      /* wait for data to come in RX fifo */
      while (I2C_MASTER_IsRXFIFOEmpty(handle)){}
      data[buffer_index++] = I2C_MASTER_GetReceivedByte(handle);
    }
    } /* end of while (temp_index < count) */
  } /* end of else */

    if (send_stop == true)
    {
      handle->runtime->bus_acquired = false;
      I2C_MASTER_SendStop(handle);
    }
  }

  return (status);
}
#endif
